/*
 * PushSender.cpp
 *
 *  Created on: 2013. 11. 15.
 *      Author: jjaehuny
 */

#include "PushSender.h"

#include <algorithm>

#include <curl/curl.h>
#include <json/json.h>

#include "../macro.h"
#include "../Config.h"
#include "../Static.h"

#include "Static.h"

namespace ProjectZ { namespace NProcess {

typedef void(*GCMCallback)(void *arg);
typedef struct __GCMCallbackData
{
	GCMCallback func;
	void            *arg;
} GCMCallbackData;

struct MemoryStruct {
	char *memory;
	size_t size;
	GCMCallbackData *CallbackData;
};

static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
	size_t realsize = size * nmemb;
	struct MemoryStruct *mem = (struct MemoryStruct *)userp;

	mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
	if (mem->memory == NULL)
	{
		/* out of memory! */
		fprintf(stderr, "not enough memory (realloc returned NULL), abort!!\n");
		return 0;
	}

	memcpy(&(mem->memory[mem->size]), contents, realsize);
	mem->size += realsize;
	mem->memory[mem->size] = 0;

	return realsize;
}


//static void call_back(void * arg)
//{
//}

PushSender::PushSender() : _clsThreadPool(2)
{
	// TODO Auto-generated constructor stub
}

PushSender::~PushSender() {
	// TODO Auto-generated destructor stub
}

//void
//PushSender::Push(Param & param)
//{
//	//sendIOS(param);
//	std::lock_guard<std::mutex> lock(_mutex);
//	{
//		_clsParamVector.push_back(param);
//	}
//
//	_clsThreadPool.PostTask(std::bind(&PushSender::work, this));
//}

void
PushSender::Push(Param * pParam)
{
	//sendIOS(param);
	{
		std::lock_guard<std::mutex> lock(_mutex);
		_clsParamVector2.push_back(pParam);
	}

	//_clsThreadPool.PostTask(std::bind(&PushSender::work2, this));

	::ProjectZ::Static::Instance().GetThreadPool().PostTask(std::bind(&PushSender::work2, this));
}

void
PushSender::Flush()
{
	std::lock_guard<std::mutex> lock(_mutex);
	std::for_each(_clsParamVectorPost.begin(), _clsParamVectorPost.end(), [&](Param & param) {
		_clsParamVector.push_back(param);
	} );

	_clsParamVectorPost.clear();

	_clsThreadPool.PostTask(std::bind(&PushSender::work, this));
}

void
PushSender::work()
{
	Param param;
	while (true)
	{
		{
			std::lock_guard<std::mutex> lock(_mutex);
			if (_clsParamVector.size() <= 0 )
				break;

			param = _clsParamVector.front();
			_clsParamVector.pop_front();
		}

		if (param._eType == Param::Type::IOS)
		{
			sendIOS(param);
		}
		else if (param._eType == Param::Type::ANDROID)
		{
			sendAnd(param);
		}
		else
		{

		}
	}
}

void
PushSender::work2()
{
	Param * param;
	while (true)
	{
		{
			std::lock_guard<std::mutex> lock(_mutex);
			if (_clsParamVector2.size() <= 0 )
				break;

			param = _clsParamVector2.front();
			_clsParamVector2.pop_front();
		}

		if (NULL == param)
			return;

		if (param->_eType == Param::Type::IOS)
		{
			sendIOS(* param);
		}
		else if (param->_eType == Param::Type::ANDROID)
		{
			sendAnd(* param);
		}
		else
		{

		}

		if (NULL != param)
			Static::Instance().GetParamPool()->SAFE_DEL(param);
	}
}


void
PushSender::sendIOS(Param & param)
{
//	int k;
	struct curl_slist * headmsg = NULL;
	char public_key[1024];

	memset( public_key, 0x00, sizeof(public_key) );
	sprintf( public_key, "GV-API-KEY:2b5b97b6aaecea5ae3a47adf2a6b4890");
	headmsg = curl_slist_append( headmsg, public_key );

	json_object *arr_jstr = json_object_new_array();
	json_object *jobj_send_body = json_object_new_object();

	{
		json_object *jstr = json_object_new_string("ios");
		json_object_object_add(jobj_send_body, "platform", jstr );
	}

	{
		json_object *jstr = json_object_new_string("27389");
		json_object_object_add(jobj_send_body, "gid", jstr );
	}

	{
		json_object *jstr = json_object_new_string("38");
		json_object_object_add(jobj_send_body, "sale_code", jstr );
	}

	{
		json_object *arr_jstr1 = json_object_new_string(param._uuid.c_str());
		json_object_array_add( arr_jstr, arr_jstr1 );
		json_object_object_add(jobj_send_body, "target_uuids", arr_jstr );
	}

	{
		json_object *jstr = json_object_new_string(param._message.c_str());
		json_object_object_add(jobj_send_body, "message", jstr );
	}

	{
		json_object *jstr = json_object_new_string("OK");
		json_object_object_add(jobj_send_body, "right_button", jstr );
	}

	{
		json_object *jstr = json_object_new_string("1");
		json_object_object_add(jobj_send_body, "badge", jstr );
	}

	{
		json_object *jstr = json_object_new_string("default");
		json_object_object_add(jobj_send_body, "sound", jstr );
	}

	const char *postmsg = json_object_to_json_string(jobj_send_body);
	int postlen = strlen(postmsg);

	DEBUGLOG("body[%d:%s]\n", postlen, postmsg );

	// post to send
	CURL *curl;
	CURLcode res;
	struct MemoryStruct chunk;
	chunk.memory = (char *)malloc(1);
	chunk.size = 0;
	chunk.CallbackData = NULL;
	curl = curl_easy_init();

	struct curl_slist *headers = NULL;
	curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postlen);

	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
		curl_easy_setopt(curl, CURLOPT_URL, "http://push3t.gamevil.com/api/s_send_push.php?encoding=json" );
	else
		curl_easy_setopt(curl, CURLOPT_URL, "http://push3.gamevil.com/api/s_send_push.php?encoding=json" );

	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postmsg);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);    /**/
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headmsg );
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);

	res = curl_easy_perform(curl);

	fprintf(stderr, "after %d:%s\n", res, chunk.memory);
	fprintf(stderr, "error:%s\n", curl_easy_strerror(res));

	curl_easy_cleanup(curl);
	curl_slist_free_all(headers);

	int ret_status = -1;

	if( res == CURLE_OK ) {
			DEBUGLOG("curl_easy_perform result=%s\n", (char*)chunk.memory);
	}
	else {
			ret_status = res;
			DEBUGLOG("curl_easy_perform not CURLE_OK result=%d\n", ret_status);
	}

	json_object_put(jobj_send_body);
	json_object_put(arr_jstr);
	free(chunk.memory);
}

void
PushSender::sendAnd(Param & param)
{
//	int k;
	struct curl_slist * headmsg = NULL;
	char public_key[1024];

	memset( public_key, 0x00, sizeof(public_key) );
	sprintf( public_key, "GV-API-KEY:2b5b97b6aaecea5ae3a47adf2a6b4890");
	headmsg = curl_slist_append( headmsg, public_key );

	json_object *arr_jstr = json_object_new_array();
	json_object *jobj_send_body = json_object_new_object();

	{
		json_object *jstr = json_object_new_string("android");
		json_object_object_add(jobj_send_body, "platform", jstr );
	}

	{
		json_object *jstr = json_object_new_string("27389");
		json_object_object_add(jobj_send_body, "gid", jstr );
	}

	{
		json_object *jstr = json_object_new_string("37");
		json_object_object_add(jobj_send_body, "sale_code", jstr );
	}


	{
		json_object *arr_jstr1 = json_object_new_string(param._uuid.c_str());
		json_object_array_add( arr_jstr, arr_jstr1 );
		json_object_object_add(jobj_send_body, "target_uuids", arr_jstr );
	}

	{
		json_object *jstr = json_object_new_string(param._message.c_str());
		json_object_object_add(jobj_send_body, "message", jstr );
	}

	{
		json_object *jstr = json_object_new_string("gamevil");
		json_object_object_add(jobj_send_body, "right_button", jstr );
	}

	{
		json_object *jstr = json_object_new_string(param._sender.c_str());
		json_object_object_add(jobj_send_body, "sender", jstr );
	}

	{
		json_object *jstr = json_object_new_string("TEST");
		json_object_object_add(jobj_send_body, "title", jstr );
	}

	{
		json_object *jstr = json_object_new_string("gamevil");
		json_object_object_add(jobj_send_body, "left_button", jstr );
	}

	{
		json_object *jstr = json_object_new_string("");
		json_object_object_add(jobj_send_body, "callback_url", jstr );
	}

	{
		json_object *jstr = json_object_new_string("1");
		json_object_object_add(jobj_send_body, "push_type", jstr );
	}

	{
		json_object *jstr = json_object_new_string("1");
		json_object_object_add(jobj_send_body, "display_type", jstr );
	}

	{
		json_object *jstr = json_object_new_string("10");
		json_object_object_add(jobj_send_body, "popup_time", jstr );
	}

	{
		json_object *jstr = json_object_new_string("");
		json_object_object_add(jobj_send_body, "banner_img", jstr );
	}

//	{
//		json_object *jstr = json_object_new_string("1");
//		json_object_object_add(jobj_send_body, "badge", jstr );
//	}
//
//	{
//		json_object *jstr = json_object_new_string("default");
//		json_object_object_add(jobj_send_body, "sound", jstr );
//	}

	const char *postmsg = json_object_to_json_string(jobj_send_body);
	int postlen = strlen(postmsg);

	DEBUGLOG("body[%d:%s]\n", postlen, postmsg );

	// post to send
	CURL *curl;
	CURLcode res;
	struct MemoryStruct chunk;
	chunk.memory = (char *)malloc(1);
	chunk.size = 0;
	chunk.CallbackData = NULL;
	curl = curl_easy_init();

	struct curl_slist *headers = NULL;
	curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postlen);

	if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
		curl_easy_setopt(curl, CURLOPT_URL, "http://push3t.gamevil.com/api/s_send_push.php?encoding=json" );
	else
		curl_easy_setopt(curl, CURLOPT_URL, "http://push3.gamevil.com/api/s_send_push.php?encoding=json" );

	curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 1);
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15);
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postmsg);
	curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);    /**/
	curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headmsg );
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);

	res = curl_easy_perform(curl);

	fprintf(stderr, "after %d:%s\n", res, chunk.memory);
	fprintf(stderr, "error:%s\n", curl_easy_strerror(res));

	curl_easy_cleanup(curl);
	curl_slist_free_all(headers);

	int ret_status = -1;

	if( res == CURLE_OK ) {
		DEBUGLOG("curl_easy_perform result=%s\n", (char*)chunk.memory);
	}
	else {
			ret_status = res;
			DEBUGLOG("curl_easy_perform result=%d\n", ret_status);
	}

	json_object_put(jobj_send_body);
	json_object_put(arr_jstr);
	free(chunk.memory);
}

} /*NProcess*/ } /*ProjectZ*/

